"""
SQL语义分析器 (Semantic Analyzer)
执行语义分析，包括类型检查、符号表管理和语义错误检测
"""

from typing import Dict, List, Set, Optional, Any
from .parser import *


class SymbolTable:
    """符号表"""

    def __init__(self):
        self.tables: Dict[str, TableInfo] = {}
        self.current_scope: Optional[str] = None

    def add_table(self, table_name: str, table_info: 'TableInfo'):
        """添加表定义"""
        self.tables[table_name.lower()] = table_info

    def get_table(self, table_name: str) -> Optional['TableInfo']:
        """获取表信息"""
        return self.tables.get(table_name.lower())

    def has_table(self, table_name: str) -> bool:
        """检查表是否存在"""
        return table_name.lower() in self.tables


class TableInfo:
    """表信息"""

    def __init__(self, name: str):
        self.name = name
        self.columns: Dict[str, ColumnInfo] = {}
        self.primary_key: Optional[str] = None
        self.constraints: List[str] = []

    def add_column(self, column_info: 'ColumnInfo'):
        """添加列"""
        self.columns[column_info.name.lower()] = column_info
        if 'PRIMARY KEY' in column_info.constraints:
            self.primary_key = column_info.name.lower()

    def get_column(self, column_name: str) -> Optional['ColumnInfo']:
        """获取列信息"""
        return self.columns.get(column_name.lower())

    def has_column(self, column_name: str) -> bool:
        """检查列是否存在"""
        return column_name.lower() in self.columns


class ColumnInfo:
    """列信息"""

    def __init__(self, name: str, data_type: str, constraints: List[str] = None):
        self.name = name
        self.data_type = data_type
        self.constraints = constraints or []
        self.not_null = 'NOT NULL' in self.constraints
        self.unique = 'UNIQUE' in self.constraints
        self.primary_key = 'PRIMARY KEY' in self.constraints


class SemanticAnalyzer:
    """语义分析器"""

    def __init__(self):
        self.symbol_table = SymbolTable()
        self.errors: List[str] = []
        self.warnings: List[str] = []

    def analyze(self, statements: List[Statement]) -> bool:
        """执行语义分析"""
        self.errors.clear()
        self.warnings.clear()

        for statement in statements:
            self.analyze_statement(statement)

        return len(self.errors) == 0

    def analyze_statement(self, statement: Statement):
        """分析语句"""
        if isinstance(statement, CreateTableStatement):
            self.analyze_create_table(statement)
        elif isinstance(statement, InsertStatement):
            self.analyze_insert(statement)
        elif isinstance(statement, UpdateStatement):
            self.analyze_update(statement)
        elif isinstance(statement, DeleteStatement):
            self.analyze_delete(statement)
        elif isinstance(statement, SelectStatement):
            self.analyze_select(statement)
        elif isinstance(statement, DropTableStatement):
            self.analyze_drop_table(statement)

    def analyze_create_table(self, statement: CreateTableStatement):
        """分析CREATE TABLE语句"""
        table_name = statement.table_name.lower()

        # 检查表是否已存在
        if self.symbol_table.has_table(table_name):
            self.errors.append(f"表 '{statement.table_name}' 已存在")
            return

        # 创建表信息
        table_info = TableInfo(statement.table_name)

        # 分析列定义
        column_names = set()
        primary_key_count = 0

        for col_def in statement.columns:
            col_name = col_def.column_name.lower()

            # 检查列名是否重复
            if col_name in column_names:
                self.errors.append(f"表 '{statement.table_name}' 中的列 '{col_def.column_name}' 重复")
                continue
            column_names.add(col_name)

            # 检查约束
            if 'PRIMARY KEY' in col_def.constraints:
                primary_key_count += 1
                if primary_key_count > 1:
                    self.errors.append(f"表 '{statement.table_name}' 有多个主键")

            # 创建列信息
            column_info = ColumnInfo(col_def.column_name, col_def.data_type, col_def.constraints)
            table_info.add_column(column_info)

        # 添加表到符号表
        self.symbol_table.add_table(statement.table_name, table_info)

    def analyze_insert(self, statement: InsertStatement):
        """分析INSERT语句"""
        table_name = statement.table_name.lower()

        # 检查表是否存在
        table_info = self.symbol_table.get_table(table_name)
        if not table_info:
            self.errors.append(f"表 '{statement.table_name}' 不存在")
            return

        # 检查列列表
        if statement.columns:
            for col_name in statement.columns:
                if not table_info.has_column(col_name):
                    self.errors.append(f"表 '{statement.table_name}' 中没有列 '{col_name}'")
                    return

            # 检查值列表长度是否匹配
            if len(statement.columns) != len(statement.values[0]):
                self.errors.append(f"列数量 ({len(statement.columns)}) 与值数量 ({len(statement.values[0])}) 不匹配")
                return
        else:
            # 如果没有指定列，使用所有列
            if len(table_info.columns) != len(statement.values[0]):
                self.errors.append(f"列数量 ({len(table_info.columns)}) 与值数量 ({len(statement.values[0])}) 不匹配")
                return

        # 分析值表达式
        for row in statement.values:
            for i, expr in enumerate(row):
                self.analyze_expression(expr, table_info)

    def analyze_update(self, statement: UpdateStatement):
        """分析UPDATE语句"""
        table_name = statement.table_name.lower()

        # 检查表是否存在
        table_info = self.symbol_table.get_table(table_name)
        if not table_info:
            self.errors.append(f"表 '{statement.table_name}' 不存在")
            return

        # 分析赋值操作
        for assignment in statement.assignments:
            col_name = assignment.column_name.lower()

            # 检查列是否存在
            if not table_info.has_column(col_name):
                self.errors.append(f"表 '{statement.table_name}' 中没有列 '{assignment.column_name}'")
                continue

            # 分析赋值表达式
            self.analyze_expression(assignment.expression, table_info)

        # 分析WHERE子句
        if statement.where_clause:
            self.analyze_expression(statement.where_clause, table_info)

    def analyze_delete(self, statement: DeleteStatement):
        """分析DELETE语句"""
        table_name = statement.table_name.lower()

        # 检查表是否存在
        table_info = self.symbol_table.get_table(table_name)
        if not table_info:
            self.errors.append(f"表 '{statement.table_name}' 不存在")
            return

        # 分析WHERE子句
        if statement.where_clause:
            self.analyze_expression(statement.where_clause, table_info)

    def analyze_select(self, statement: SelectStatement):
        """分析SELECT语句"""
        table_name = statement.from_clause.table_name.lower()

        # 检查表是否存在
        table_info = self.symbol_table.get_table(table_name)
        if not table_info:
            self.errors.append(f"表 '{statement.from_clause.table_name}' 不存在")
            return

        # 分析选择列表
        for expr in statement.select_list:
            self.analyze_expression(expr, table_info)

        # 分析WHERE子句
        if statement.where_clause:
            self.analyze_expression(statement.where_clause, table_info)

    def analyze_drop_table(self, statement: DropTableStatement):
        """分析DROP TABLE语句"""
        table_name = statement.table_name.lower()

        # 检查表是否存在
        if not self.symbol_table.has_table(table_name):
            self.errors.append(f"表 '{statement.table_name}' 不存在")
            return

    def analyze_expression(self, expression: Expression, table_info: TableInfo):
        """分析表达式"""
        if isinstance(expression, ColumnReference):
            col_name = expression.column_name.lower()
            if col_name != '*' and not table_info.has_column(col_name):
                self.errors.append(f"表 '{table_info.name}' 中没有列 '{expression.column_name}'")

        elif isinstance(expression, BinaryExpression):
            self.analyze_expression(expression.left, table_info)
            self.analyze_expression(expression.right, table_info)

        elif isinstance(expression, UnaryExpression):
            self.analyze_expression(expression.operand, table_info)

        elif isinstance(expression, FunctionCall):
            for arg in expression.arguments:
                self.analyze_expression(arg, table_info)

        # Literal和FunctionCall不需要特殊处理


def test_semantic_analyzer():
    """测试语义分析器"""
    from .lexer import Lexer
    from .parser import Parser

    sql = """
    CREATE TABLE users (
        id INT PRIMARY KEY,
        name VARCHAR(50) NOT NULL,
        age INT,
        email VARCHAR(100)
    );

    INSERT INTO users VALUES (1, 'Alice', 25, 'alice@example.com');
    INSERT INTO users (id, name) VALUES (2, 'Bob');

    SELECT id, name FROM users WHERE age > 20;
    SELECT * FROM users WHERE invalid_column = 1;

    UPDATE users SET age = 26 WHERE id = 1;
    UPDATE invalid_table SET name = 'Charlie' WHERE id = 1;

    DROP TABLE users;
    DROP TABLE invalid_table;
    """

    lexer = Lexer(sql)
    tokens = lexer.tokenize()

    parser = Parser(tokens)
    statements = parser.parse()

    analyzer = SemanticAnalyzer()
    success = analyzer.analyze(statements)

    print("语义分析结果:")
    print(f"分析成功: {success}")

    if analyzer.errors:
        print("\n错误:")
        for error in analyzer.errors:
            print(f"  - {error}")

    if analyzer.warnings:
        print("\n警告:")
        for warning in analyzer.warnings:
            print(f"  - {warning}")


if __name__ == "__main__":
    test_semantic_analyzer()
